package com.springleaf.common.display
{
	import com.springleaf.common.event.UILoadEvent;
	import com.springleaf.common.event.UIMouseEvent;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	public class UISprite extends Sprite
	{
		private var startPoint:Point = new Point(0, 0);
		private var localMousePoint:Point = new Point(0, 0);
		private var globalMousePoint:Point = localToGlobal(localMousePoint);
		private var eventsActivated:Boolean = false;
		
		private var _alphaTolerance:uint = 1;
		private var _bitmap:Bitmap;
		private var _canvas:BitmapData;
		private var _sheet:BitmapData;
		private var _defaultSize:Rectangle;
		
		/**
		 * After creating the object, don't forget to set the sheet amd the defaultSize.
		 * After doing so you should call the draw() method to display and render to update 
		 * without instanciation.
		 */
		public function UISprite() {
			addGlobalEventListeners();
		}
		
		/**
		 * Use this method to display your sprite but only after you are sure you added 
		 * the sheet and defaultSize, else it won't do a thing.
		 */
		public function draw():void {
			if (_sheet && _defaultSize) {
				if (!_bitmap) {
					_canvas = new BitmapData(_defaultSize.width, _defaultSize.height, true, 0);
					_bitmap = new Bitmap(_canvas);
					_bitmap.x = -_defaultSize.width * 0.5;
					_bitmap.y = -_defaultSize.height;
					addChild(_bitmap);
				}
			}
		}
		
		/**
		 * Use this method to update the display of the bitmap, but only after you are sure
		 * you added the sheet and defaultSize and called the draw() method.
		 */
		public function render(rectangle:Rectangle, currentPoint:Point = null):void {
			if (_bitmap) {
				if (!currentPoint) {
					currentPoint = startPoint;
				}
				_canvas.fillRect(_canvas.rect, 1);
				_canvas.copyPixels(sheet, rectangle, currentPoint);
			}
		}
		
		/**
		 * Voodoo Magic. So, it's something like this: the first event is ROLL_OVER
		 * that will be negated in onRollOver(). Next, a MOUSE_OVER event will be dispatched 
		 * that will be catched in onMouseOver(). In the same time an ENTER_FRAME event
		 * listener will be added for the hitTest and to disable the mouse. When the mouse
		 * is disabled a MOUSE_OUT event will be dispatched and it will be catched by
		 * onMouseOut(), negated, and all the listeners will be removed.
		 */
		private function addGlobalEventListeners():void {
			addEventListener(MouseEvent.MOUSE_OUT, onMouseOut, false, 1000, true);
			addEventListener(MouseEvent.MOUSE_OVER, onMouse, false, 1000, true);
			addEventListener(MouseEvent.ROLL_OVER, onRollOver, false, 1000, true);
		}
		
		private function removeGlobalEventListeners():void {
			removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
			removeEventListener(MouseEvent.MOUSE_OVER, onMouse);
			removeEventListener(MouseEvent.ROLL_OVER, onRollOver);
		}
		
		private function onMouseOut(event:MouseEvent):void {
			event.stopImmediatePropagation();
			removeGlobalEventListeners();
		}
		
		private function onMouse(event:MouseEvent):void {
			event.stopImmediatePropagation();
			addEventListener(Event.ENTER_FRAME, onFrame, false, 1, true);
		}
		
		private function onRollOver(event:MouseEvent):void {
			event.stopImmediatePropagation();
		}
		
		private function onFrame(event:Event):void {
			if (localHitTest()) {
				trace("Local");
				mouseEnabled = true;
			} else {
				trace("Global");
				mouseEnabled = false;
				if (!globalHitTest()) {
					trace("None");
					removeEventListener(Event.ENTER_FRAME, onFrame);
					addGlobalEventListeners();
					mouseEnabled = true;
				}
			}
		}
		
		private function localHitTest():Boolean {
			localMousePoint.x = _bitmap.mouseX;
			localMousePoint.y = _bitmap.mouseY;
			return _canvas.hitTest(startPoint, _alphaTolerance, localMousePoint);
		}
		
		private function globalHitTest():Boolean {
			globalMousePoint = localToGlobal(new Point(mouseX, mouseY));
			return hitTestPoint(globalMousePoint.x, globalMousePoint.y);
		}
		
		private function dispatchMouseEvent(event:String):void {
			dispatchEvent(new UIMouseEvent(event));
		}
		
		public function get defaultSize():Rectangle
		{
			return _defaultSize;
		}

		public function set defaultSize(value:Rectangle):void
		{
			_defaultSize = value;
		}

		public function get sheet():BitmapData
		{
			return _sheet;
		}

		public function set sheet(value:BitmapData):void
		{
			_sheet = value;
		}

		public function get alphaTolerance():uint
		{
			return _alphaTolerance;
		}

		public function set alphaTolerance(value:uint):void
		{
			_alphaTolerance = Math.min(value, 255);
		}

	}
}